package org.rcy.framework.thrift.serializer;

import net.qiyuesuo.rpc.thrift.metadata.ExceptionData;
import net.qiyuesuo.rpc.thrift.metadata.FieldValueMetaData;
import net.qiyuesuo.rpc.thrift.metadata.StructMetaData;
import net.qiyuesuo.rpc.thrift.tbase.ExceptionStruct;
import org.apache.thrift.TException;
import org.apache.thrift.protocol.TField;
import org.apache.thrift.protocol.TProtocol;
import org.apache.thrift.protocol.TProtocolUtil;
import org.apache.thrift.protocol.TStruct;
import org.apache.thrift.protocol.TType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class ExceptionSerializer implements Serializer {

	private Logger logger = LoggerFactory.getLogger(getClass());
	
	protected static final TStruct ANONYMOUS_STRUCT = new TStruct();

	@Override
	public Object read(TProtocol iprot, FieldValueMetaData valueMetaData) throws TException {
		iprot.readStructBegin();
		// className字段
		iprot.readFieldBegin();
		String className = iprot.readString();
		iprot.readFieldEnd();
		
		// message字段
		iprot.readFieldBegin();
		String message = iprot.readString();
		iprot.readFieldEnd();

		// exception字段
		Exception exception = new Exception(message);
		try{
			Class clazz = Class.forName(className);
			StructMetaData structMetaData = new StructMetaData(clazz);
			
			ExceptionStruct struct = new ExceptionStruct(structMetaData,null);
			iprot.readFieldBegin();
			struct.read(iprot);
			iprot.readFieldEnd();

			exception = (Exception)struct.getStructObject();
		} catch (Exception e) {
			//异常类不存在或者无法实例化
			logger.warn(e.getMessage());
		}
		
		while (true) {
			// scheme字段
			TField schemeField = iprot.readFieldBegin();
			if (schemeField.type == TType.STOP) {
				break;
			}
			TProtocolUtil.skip(iprot, schemeField.type);
			iprot.readFieldEnd();
		}
		
		iprot.readStructEnd();
		return  new ExceptionData(exception);
	}

	@Override
	public void write(TProtocol oprot, FieldValueMetaData valueMetaData, Object value) throws TException {
		ExceptionData ed = (ExceptionData) value;

		oprot.writeStructBegin(ANONYMOUS_STRUCT);

		// 写className字段
		TField clazzField = new TField("clazz", TType.STRING, (short) 1);
		String className = ed.getClassName();
		oprot.writeFieldBegin(clazzField);
		oprot.writeString(className);
		oprot.writeFieldEnd();
		// 写message字段
		TField messageField = new TField("message", TType.STRING, (short) 2);
		String message = ed.getMessage();
		oprot.writeFieldBegin(messageField);
		oprot.writeString(message);
		oprot.writeFieldEnd();

		// 写exception字段
		TField exceptionField = new TField("exception", TType.STRUCT, (short) 3);
		Object exception = ed.getException();

		try {
			Class exceptionClass = Class.forName(className);
			StructMetaData structMetaData = new StructMetaData(exceptionClass);
			ExceptionStruct struct = new ExceptionStruct(structMetaData,exception);

			oprot.writeFieldBegin(exceptionField);
			struct.write(oprot);
			oprot.writeFieldEnd();
		} catch (ClassNotFoundException e) {
			logger.error(e.getMessage(), e);
		}

		oprot.writeFieldStop();
		oprot.writeStructEnd();
	}
}
